package com.yst.webplugin.fieldhandler;

import com.yst.executor.Page;
import com.yst.sqlbuilder.SQLSelect;
import com.yst.sqlbuilder.SQLSelectCondition;
import com.yst.sqlbuilder.Symbol;
import com.yst.web.utils.ClassUtils;
import com.yst.web.utils.JsonConverter;
import com.yst.webplugin.additional.ResultProcessor;
import com.yst.webplugin.additional.mask.MaskConfigUtil;
import com.yst.webplugin.additional.transform.TransformConfigUtil;
import com.yst.webplugin.annotation.Filter;
import com.yst.webplugin.annotation.HttpInfo;
import com.yst.webplugin.annotation.QueryTable;
import com.yst.webplugin.util.ParamUtils;
import com.yst.webplugin.util.ReqParamsUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.*;

public class QueryTableHandler implements IFieldHandler{
    @Override
    public boolean accept(Field field) {
        return Objects.nonNull(field.getAnnotation(QueryTable.class));
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Accessors(chain = true)
    public static class FilterItem implements Serializable {
        private String fieldName;
        private String symbol;
        private Object value;
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Accessors(chain = true)
    public static class FilterGroup implements Serializable {
        private List<FilterItem> conditions=new LinkedList<>();
    }

    @Override
    public void handle(Field field, HttpInfo httpInfo) {

        FilterGroup filterGroup=httpInfo.getBodyAs(FilterGroup.class);

        QueryTable queryTable=field.getAnnotation(QueryTable.class);
        SQLSelect<?> sqlSelect=new SQLSelect<>().from((Class<Object>) queryTable.modelClass())
                .select(queryTable.selectedFields())
                .disableSelect(queryTable.disableFields())
                .where((w)->{
                    for(Filter filter:queryTable.filters()){
                        w.compare(filter.field(), Symbol.fromString(filter.symbol().symbol),filter.value());
                    }
                    if (!filterGroup.conditions.isEmpty()){
                        for(FilterItem item:filterGroup.conditions){
                            if (ReqParamsUtils.isArray(item.fieldName)){
                                List<String> fields=JsonConverter.getJsonConverter().parseList(item.fieldName,String.class);
                                SQLSelectCondition.SubSQLCondition<?> subSQLCondition=w.or();
                                for(String fieldName:fields){
                                    subSQLCondition.compare(fieldName,Symbol.fromString(item.symbol),item.value);
                                }
                            }
                            else {
                                w.compare(item.fieldName, Symbol.fromString(item.symbol), item.value);
                            }
                        }
                    }
                })
                .orderBy((o)->{
                    o.orderBy(queryTable.orderBy());
                });

        ResultProcessor processor=new ResultProcessor()
                .addAllFieldMaskConfig(MaskConfigUtil.fromField(field))
                .addAllTransformConfig(TransformConfigUtil.fromField(field))
                .addAllTransformConfig(TransformConfigUtil.fromClass(queryTable.modelClass()))
                .disableField(queryTable.disableFields());

        if (ClassUtils.isAssignableFrom(field.getType(), Collection.class)) {
            List<?> dataList = sqlSelect.getList();
            processor.deepProcess(dataList, queryTable.modelClass());
            httpInfo.writeResult(dataList);
            return;
        }

        if (ClassUtils.isAssignableFrom(field.getType(), Page.PageOut.class)) {
            Page.PageIn page=httpInfo.getBodyAs(Page.PageIn.class);
            Page.PageOut dataList = sqlSelect.getPage(page);
            processor.deepProcess(dataList.getDataList(), queryTable.modelClass());
            httpInfo.writeResult(dataList);
        }
    }
}
